package impl

import (
	"context"
	"gitee.com/kordar/bucket/model"
	"gitee.com/kordar/bucket/service"
	"gitee.com/kordar/bucket/util"
	logger "github.com/kordar/gologger"
	"github.com/kordar/goupload"
	"mime/multipart"
)

type BucketUploaderServiceImpl struct {
	context       context.Context
	bucketService service.BucketService
}

func NewBucketUploaderServiceImpl(bucketService service.BucketService) *BucketUploaderServiceImpl {
	return &BucketUploaderServiceImpl{bucketService: bucketService, context: context.Background()}
}

func (b *BucketUploaderServiceImpl) getBucketHandler(id int64) (goupload.BucketUploader, error) {
	bucketModel, err := b.bucketService.GetBucket(id)
	if err != nil {
		return nil, err
	}

	handler, err := util.GetBucketHandler(bucketModel)
	if err != nil {
		return nil, err
	}

	return handler, nil
}

func (b *BucketUploaderServiceImpl) Upload(id int64, targetFilePath string, file *multipart.FileHeader) error {
	handler, err := b.getBucketHandler(id)
	if err != nil {
		return err
	}

	srcfile, err := file.Open()
	if err != nil {
		return err
	}
	defer srcfile.Close()

	return handler.Put(b.context, targetFilePath, srcfile)
}

func (b *BucketUploaderServiceImpl) Download(id int64, filename string) ([]byte, error) {
	handler, err := b.getBucketHandler(id)
	if err != nil {
		return nil, err
	}

	return handler.Get(b.context, filename)
}

func (b *BucketUploaderServiceImpl) DownloadToFile(id int64, filename string, targetLocalPath string) error {
	handler, err := b.getBucketHandler(id)
	if err != nil {
		return err
	}

	return handler.GetToFile(b.context, filename, targetLocalPath)
}

func (b *BucketUploaderServiceImpl) UploadFromFile(id int64, targetFilePath string, sourceFilePath string) error {
	handler, err := b.getBucketHandler(id)
	if err != nil {
		return err
	}

	return handler.PutFromFile(b.context, targetFilePath, sourceFilePath)
}

func (b *BucketUploaderServiceImpl) List(id int64, dir string, next interface{}, page int, limit int, subCount bool) ([]goupload.BucketObject, interface{}) {
	handler, err := b.getBucketHandler(id)
	if err != nil {
		logger.Warnf("list bucket handler error, %s", err.Error())
		return []goupload.BucketObject{}, err
	}

	if handler.Driver() == model.CosDriver {
		return handler.List(b.context, dir, next, limit, subCount)
	}

	return handler.List(b.context, dir, page, limit, subCount)
}

func (b *BucketUploaderServiceImpl) Count(id int64, dir string) int {
	handler, err := b.getBucketHandler(id)
	if err != nil {
		logger.Warnf("count bucket handler error, %s", err.Error())
		return 0
	}

	return handler.Count(b.context, dir)
}

func (b *BucketUploaderServiceImpl) Del(id int64, name string) error {
	handler, err := b.getBucketHandler(id)
	if err != nil {
		return err
	}

	return handler.Del(b.context, name)
}

func (b *BucketUploaderServiceImpl) DelAll(id int64, dir string) {
	handler, err := b.getBucketHandler(id)
	if err != nil {
		logger.Warnf("del bucket handler error, %s", err.Error())
		return
	}

	handler.DelAll(b.context, dir)
}

func (b *BucketUploaderServiceImpl) DelMulti(id int64, objects []goupload.BucketObject) error {
	handler, err := b.getBucketHandler(id)
	if err != nil {
		return err
	}

	return handler.DelMulti(b.context, objects)
}

func (b *BucketUploaderServiceImpl) IsExist(id int64, name string) (bool, error) {
	handler, err := b.getBucketHandler(id)
	if err != nil {
		return false, err
	}

	return handler.IsExist(b.context, name)
}

func (b *BucketUploaderServiceImpl) Copy(id int64, dest string, source string) error {
	handler, err := b.getBucketHandler(id)
	if err != nil {
		return err
	}

	return handler.Copy(b.context, dest, source)
}

func (b *BucketUploaderServiceImpl) Move(id int64, dest string, source string) error {
	handler, err := b.getBucketHandler(id)
	if err != nil {
		return err
	}

	return handler.Move(b.context, dest, source)
}

func (b *BucketUploaderServiceImpl) Rename(id int64, dest string, source string) error {
	handler, err := b.getBucketHandler(id)
	if err != nil {
		return err
	}

	return handler.Rename(b.context, dest, source)
}

func (b *BucketUploaderServiceImpl) Tree(id int64, dir string, next interface{}, page int, limit int, dep int, maxDep int, noleaf bool, subCount bool) []goupload.BucketTreeObject {
	handler, err := b.getBucketHandler(id)
	if err != nil {
		logger.Warnf("tree bucket handler error, %s", err.Error())
		return []goupload.BucketTreeObject{}
	}

	if handler.Driver() == model.CosDriver {
		return handler.Tree(b.context, dir, next, limit, dep, maxDep, noleaf, subCount)
	}

	return handler.Tree(b.context, dir, page, limit, dep, maxDep, noleaf, subCount)
}
